﻿/*!	@file	r_input_server_win32.cpp
	@brief	入力装置(Windows
Copyright (c) 2009 Yuya Yamaguchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "r_input_server_win32.h"
#if R_TARGET_COMMONIS(R_TARGET_COMMON_WIN32) || R_TARGET_COMMONIS(R_TARGET_COMMON_WIN64)
#include "../r_input_device_controll.h"
#include "../r_input_device_keys.h"

#include "../../window/r_window_systeminfo.h"

#include <windows.h>
#include <mmsystem.h>


#pragma comment(lib, "winmm.lib")

#include "../../rtti/r_rtti_reflection_implement.h"
namespace r{
	namespace input{
		// -----------------------------------------------
		#define JOY_BUTTON_FLAG(v)			(1 << ((v) - 1))
		// -----------------------------------------------



		static const r_si32 vkeyData[] = {
			VK_SPACE,
			VK_MENU,
			'D',
			'X',
			'Z',
			'C',
			'B',
			'N',
			'M',
			'H',
			'J',
			'K',
			'Q',
			'I',
			'W',
			'U'
		};

		static const r_ui8	keyboardMapData[] = {
			0x41,			//!< DeviceKeys_A
			0x42,			//!< DeviceKeys_B
			0x43,			//!< DeviceKeys_C
			0x44,			//!< DeviceKeys_D
			0x45,			//!< DeviceKeys_E
			0x46,			//!< DeviceKeys_F
			0x47,			//!< DeviceKeys_G
			0x48,			//!< DeviceKeys_H
			0x49,			//!< DeviceKeys_I
			0x4a,			//!< DeviceKeys_J
			0x4b,			//!< DeviceKeys_K
			0x4c,			//!< DeviceKeys_L
			0x4d,			//!< DeviceKeys_M
			0x4e,			//!< DeviceKeys_N
			0x4f,			//!< DeviceKeys_O
			0x50,			//!< DeviceKeys_P
			0x51,			//!< DeviceKeys_Q
			0x52,			//!< DeviceKeys_R
			0x53,			//!< DeviceKeys_S
			0x54,			//!< DeviceKeys_T
			0x55,			//!< DeviceKeys_U
			0x56,			//!< DeviceKeys_V
			0x57,			//!< DeviceKeys_W
			0x58,			//!< DeviceKeys_X
			0x59,			//!< DeviceKeys_Y
			0x5a,			//!< DeviceKeys_Z
			VK_ESCAPE,		//!< DeviceKeys_Escape
			VK_RETURN,		//!< DeviceKeys_Enter
			VK_RETURN,		//!< DeviceKeys_Return
			VK_TAB,			//!< DeviceKeys_Tab
			VK_SPACE,		//!< DeviceKeys_Space,
			VK_DELETE,		//!< DeviceKeys_Del,
			VK_BACK,		//!< DeviceKeys_BS,
			0x00,			//!< DeviceKeys_0,
			0x00,			//!< DeviceKeys_1,
			0x00,			//!< DeviceKeys_2,
			0x00,			//!< DeviceKeys_3,
			0x00,			//!< DeviceKeys_4,
			0x00,			//!< DeviceKeys_5,
			0x00,			//!< DeviceKeys_6,
			0x00,			//!< DeviceKeys_7,
			0x00,			//!< DeviceKeys_8,
			0x00,			//!< DeviceKeys_9,
			0x00,			//!< DeviceKeys_Exc,		//!< !
			0x00,			//!< DeviceKeys_DQ,		//!< "
			0x00,			//!< DeviceKeys_No,		//!< #
			0x00,			//!< DeviceKeys_Dol,		//!< $
			0x00,			//!< DeviceKeys_Per,		//!< %
			0x00,			//!< DeviceKeys_Amp,		//!< &
			0x00,			//!< DeviceKeys_SQ,		//!< '
			0x00,			//!< DeviceKeys_LBln,	//!< (
			0x00,			//!< DeviceKeys_RBln,	//!< )
			0x00,			//!< DeviceKeys_Eq,		//!< =
			0x00,			//!< DeviceKeys_Min,		//!< -
			0x00,			//!< DeviceKeys_Cld,		//!< ~
			0x00,			//!< DeviceKeys_Hat,		//!< ^
			0x00,			//!< DeviceKeys_At,		//!< @
			0x00,			//!< DeviceKeys_Pip,		//!< |
			0x00,			//!< DeviceKeys_Sl,		//!< /
			0x00,			//!< DeviceKeys_BSl,		//!< \ 
			0x00,			//!< DeviceKeys_LBls,	//!< {
			0x00,			//!< DeviceKeys_RBls,	//!< }
			0x00,			//!< DeviceKeys_LBlk,	//!< [
			0x00,			//!< DeviceKeys_RBlk,	//!< ]
			0x00,			//!< DeviceKeys_Uber,	//!< _
			0x00,			//!< DeviceKeys_Pls,		//!< +
			0x00,			//!< DeviceKeys_Ast,		//!< *
			0x00,			//!< DeviceKeys_Cln,		//!< :
			0x00,			//!< DeviceKeys_SCln,	//!< ;
			0x00,			//!< DeviceKeys_Dot,		//!< .
			0x00,			//!< DeviceKeys_Cnm,		//!< ,
			0x00,			//!< DeviceKeys_Glt,		//!< >
			0x00,			//!< DeviceKeys_Les,		//!< <
			0x00,			//!< DeviceKeys_Qst,		//!< ?
			0x00,			//!< DeviceKeys_Bqt,		//!< `
			VK_LSHIFT,		//!< DeviceKeys_LShift,
			VK_RSHIFT,		//!< DeviceKeys_RShift,
			VK_LMENU,		//!< DeviceKeys_LAlt,
			VK_RMENU,		//!< DeviceKeys_RAlt,
			VK_LCONTROL,	//!< DeviceKeys_LCtl,
			VK_RCONTROL,	//!< DeviceKeys_RCtl,
			VK_UP,			//!< DeviceKeys_Arrow_Up,
			VK_DOWN,		//!< DeviceKeys_Arrow_Down,
			VK_LEFT,		//!< DeviceKeys_Arrow_Left,
			VK_RIGHT,		//!< DeviceKeys_Arrow_Right,
			VK_CAPITAL		//!< DeviceKeys_Caps,
		};

		static const r_ui8	keyboardNumMapData[] = {
			VK_NUMPAD0,
			VK_NUMPAD1,
			VK_NUMPAD2,
			VK_NUMPAD3,
			VK_NUMPAD4,
			VK_NUMPAD5,
			VK_NUMPAD6,
			VK_NUMPAD7,
			VK_NUMPAD8,
			VK_NUMPAD9
		};

		static const r_ui32 padAssignValue[DeviceControllKeys_DNum] = {
			JOY_BUTTON_FLAG ( 10 ),	//!< start
			JOY_BUTTON_FLAG ( 9 ),		//!< select
			0,						//!< dummy(up)
			0,						//!< dummy(down)
			0,						//!< dummy(left)
			0,						//!< dummy(right)
			JOY_BUTTON_FLAG ( 1 ),		//!< A
			JOY_BUTTON_FLAG ( 3 ),		//!< B
			JOY_BUTTON_FLAG ( 2 ),		//!< C
			JOY_BUTTON_FLAG ( 4 ),		//!< D
			JOY_BUTTON_FLAG ( 11 ),	//!< E
			JOY_BUTTON_FLAG ( 12 ),	//!< F
			JOY_BUTTON_FLAG ( 5 ),		//!< L1
			JOY_BUTTON_FLAG ( 7 ),		//!< R1
			JOY_BUTTON_FLAG ( 6 ),		//!< L2
			JOY_BUTTON_FLAG ( 8 )		//!< R2
		};

// >>>>>>>>>> RTTI >>>>>>>>>>
RRTTI_REFLECTION_IMPLEMENT ( r::input::ServerWin32, r::input::Server )
// <<<<<<<<<< RTTI <<<<<<<<<<

		ServerWin32 :: ServerWin32()
		{
			// 初期化
			for ( r_si32 i = 0; i < ServerInfo_DeviceControllNum; ++i ) {
				deviceControll[i].init();
			}
			deviceKeys.init();
		}

		ServerWin32 :: ~ServerWin32()
		{
		}

		r_si32 ServerWin32 :: getDeviceControllNum() const
		{
			r_si32 numpad = ::joyGetNumDevs();
			if ( numpad > ServerInfo_DeviceControllNum ) {
				numpad = ServerInfo_DeviceControllNum;
			}
			return numpad;
		}

		r_si32 ServerWin32 :: getDeviceKeysNum() const
		{
			return ServerInfo_DeviceKeysNum;
		}

		void ServerWin32 :: update ( void )
		{
			Params::instance inputPrams;
			beginInput();
			cRWindowSystemInfo systeminfo;
			if ( systeminfo.getHasFocus() ) {

				r_si32 numpad = getDeviceControllNum();
				for ( r_si32 i = 0; i < numpad; ++i ) {
					JOYINFOEX JoyInfoEx;
					ZeroMemory ( &JoyInfoEx, sizeof ( JOYINFOEX ) );

					// マウス情報
					if ( i == 0 ) {
						POINT mousepos;
						::GetCursorPos ( &mousepos );
						::ScreenToClient ( reinterpret_cast<HWND> ( systeminfo.getWindowhandle() ), &mousepos );
						if ( ::GetKeyState ( VK_LBUTTON ) & ( 0x1 << 16 ) ) {
							deviceControll[i].setKey ( DeviceControllKeys_PointL, true );
						}
						if ( ::GetKeyState ( VK_MBUTTON ) & ( 0x1 << 16 ) ) {
							deviceControll[i].setKey ( DeviceControllKeys_PointM, true );
						}
						if ( ::GetKeyState ( VK_RBUTTON ) & ( 0x1 << 16 ) ) {
							deviceControll[i].setKey ( DeviceControllKeys_PointR, true );
						}
						deviceControll[i].setScreen ( Screen ( mousepos.x, mousepos.y ) );
					}

					JoyInfoEx.dwSize = sizeof ( JoyInfoEx );
					JoyInfoEx.dwFlags = JOY_RETURNALL;
					if ( ::joyGetPosEx ( JOYSTICKID1 + i, &JoyInfoEx ) != JOYERR_NOERROR ) {
						for ( r_si32 j = 0; j < DeviceControllKeys_DNum; ++j ) {
							if ( ::GetKeyState ( vkeyData[j] ) & ( 0x1 << 16 ) ) {
								deviceControll[i].setKey ( j, true );
							}
						}
						continue;
					}

					// 左2Dアナログ
					{
						r_si32 v = JoyInfoEx.dwYpos - 0x7eff;
						r_si32 h = JoyInfoEx.dwXpos - 0x7eff;
						if ( v >= 0x100 ) {
							v -= 0x100;
						}
						if ( h >= 0x100 ) {
							h -= 0x100;
						}
						v >>= 4;
						h >>= 4;
						deviceControll[i].setAnalog2D ( DeviceControllKeyAnalog2D_L, Analog2D ( static_cast<r_f32> ( h ), static_cast<r_f32> ( v ) ) );
						if ( v < - ( inputPrams->analogDegitalThreasould ) ) {
							deviceControll[i].setKey ( DeviceControllKeys_Up, true );
						} else if ( v > inputPrams->analogDegitalThreasould ) {
							deviceControll[i].setKey ( DeviceControllKeys_Down, true );
						}
						if ( h < - ( inputPrams->analogDegitalThreasould ) ) {
							deviceControll[i].setKey ( DeviceControllKeys_Left, true );
						} else if ( h > inputPrams->analogDegitalThreasould ) {
							deviceControll[i].setKey ( DeviceControllKeys_Right, true );
						}
						for ( r_si32 j = 0; j < DeviceControllKeys_DNum; ++j ) {
							if ( JoyInfoEx.dwButtons & padAssignValue[j] ) {
								deviceControll[i].setKey ( j, true );
							}
						}
					}

					// 右2Dアナログ
					{
						r_si32 v = JoyInfoEx.dwRpos - 0x7eff;
						r_si32 h = JoyInfoEx.dwZpos - 0x7eff;
						if ( v >= 0x100 ) {
							v -= 0x100;
						}
						if ( h >= 0x100 ) {
							h -= 0x100;
						}
						v >>= 4;
						h >>= 4;
						deviceControll[i].setAnalog2D ( DeviceControllKeyAnalog2D_R, Analog2D ( static_cast<r_f32> ( h ), static_cast<r_f32> ( v ) ) );
					}
					deviceControll[i].setIsConnect ( true );
				}
				r_ui8 keybordstat[256];
				::GetKeyboardState ( keybordstat );

				// まずは基本割付から変換を行う
				for ( r_si32 i = 0; i < DeviceKeysNum; ++i ) {
					deviceKeys.setKey ( i, keybordstat[keyboardMapData[i]] & 0x80 ? true : false );
				}
				// 次にテンキー入力を追加する
				r_si32 n = 0;
				for ( r_si32 i = DeviceKeys_0; i <= DeviceKeys_9; ++i ) {
					if ( keybordstat[keyboardNumMapData[n]] & 0x80 ) {
						deviceKeys.setKey ( i, true );
					}
					++n;
				}
				if ( keybordstat[VK_DECIMAL] & 0x80 ) {
					deviceKeys.setKey ( DeviceKeys_Dot, true );
				}
				if ( keybordstat[VK_MULTIPLY] & 0x80 ) {
					deviceKeys.setKey ( DeviceKeys_Ast, true );
				}
				if ( keybordstat[VK_ADD] & 0x80 ) {
					deviceKeys.setKey ( DeviceKeys_Pls, true );
				}
				if ( keybordstat[VK_SUBTRACT] & 0x80 ) {
					deviceKeys.setKey ( DeviceKeys_Min, true );
				}
				if ( keybordstat[VK_DIVIDE] & 0x80 ) {
					deviceKeys.setKey ( DeviceKeys_Sl, true );
				}

				// Shift+で入力するキーを設定する
				if ( ( keybordstat[VK_LSHIFT] & 0x80 ) || ( keybordstat[VK_RSHIFT] & 0x80 ) ) {
					if ( keybordstat[0x31] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Exc, true );		// !
					}
					if ( keybordstat[0x32] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_DQ, true );		// "
					}
					if ( keybordstat[0x33] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_No, true );		// #
					}
					if ( keybordstat[0x34] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Dol, true );		// $
					}
					if ( keybordstat[0x35] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Per, true );		// %
					}
					if ( keybordstat[0x36] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Amp, true );		// &
					}
					if ( keybordstat[0x37] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_SQ, true );		// '
					}
					if ( keybordstat[0x38] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_LBln, true );		// (
					}
					if ( keybordstat[0x39] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_RBln, true );		// )
					}
					if ( keybordstat[0xbd] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Eq, true );		// =
					}
					if ( keybordstat[0xde] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Cld, true );		// ~
					}
					if ( keybordstat[0xdc] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Pip, true );		// |
					}

					if ( keybordstat[0xdb] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_LBls, true );		// {
					}
					if ( keybordstat[0xdd] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_RBls, true );		// }
					}

					if ( keybordstat[0xc0] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Bqt, true );		// `
					}
					if ( keybordstat[0xbb] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Pls, true );		// +
					}
					if ( keybordstat[0xba] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Ast, true );		// *
					}

					if ( keybordstat[0xbe] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Glt, true );		// >
					}
					if ( keybordstat[0xbc] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Les, true );		// <
					}
					if ( keybordstat[0xbf] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Qst, true );		// ?
					}
					if ( keybordstat[0xe2] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Uber, true );		// _
					}
				}
				// Shiftで無ければのキー
				else {
					if ( keybordstat[0x31] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_1, true );		// 1
					}
					if ( keybordstat[0x32] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_2, true );		// 2
					}
					if ( keybordstat[0x33] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_3, true );		// 3
					}
					if ( keybordstat[0x34] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_4, true );		// 4
					}
					if ( keybordstat[0x35] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_5, true );		// 5
					}
					if ( keybordstat[0x36] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_6, true );		// 6
					}
					if ( keybordstat[0x37] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_7, true );		// 7
					}
					if ( keybordstat[0x38] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_8, true );		// 8
					}
					if ( keybordstat[0x39] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_9, true );		// 9
					}
					if ( keybordstat[0xbd] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Min, true );		// -
					}
					if ( keybordstat[0xde] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Hat, true );		// ^
					}
					if ( keybordstat[0xdc] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_BSl, true );		// \ 
					}

					if ( keybordstat[0xdb] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_LBlk, true );		// [
					}
					if ( keybordstat[0xdd] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_RBlk, true );		// ]
					}

					if ( keybordstat[0xc0] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_At, true );		// @
					}
					if ( keybordstat[0xbb] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_SCln, true );		// ;
					}
					if ( keybordstat[0xba] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Cln, true );		// :
					}

					if ( keybordstat[0xbe] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Dot, true );		// .
					}
					if ( keybordstat[0xbc] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Cnm, true );		// ,
					}
					if ( keybordstat[0xbf] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_Sl, true );		// /
					}
					if ( keybordstat[0xe2] & 0x80 ) {
						deviceKeys.setKey ( DeviceKeys_BSl, true );		// \ 
					}
				}
			}

			endInput();
		}

		//! 入力の有/無効化
		/*! 入力を無効化した場合はそのフレーム内で帰される入力状態は無入力状態になる。
		@param	enable	[in]	入力状態の有/無効
		*/
		void ServerWin32 :: setActive ( r_bool enable )
		{
		//	Client :: isActive = enable;
		//	Keys :: isActive = enable;
		}

		//! デバイスの取得
		/*!
		@param	index	[in]	0～有効なデバイスのインデックス(無効な場合は0番目のデバイスが帰る)
		*/
		const DeviceControll*	ServerWin32 :: getDeviceControll ( r_si32 index ) const
		{
			if ( ( index >= 0 ) && ( index < ServerInfo_DeviceControllNum ) ) {
				return &deviceControll[index];
			}
			return &deviceControll[0];
		}

		const DeviceKeys*	ServerWin32 :: getDeviceKeys ( r_si32 index ) const
		{
			return &deviceKeys;
		}


		// キー入力開始
		/*!
		*/
		void ServerWin32 :: beginInput ( void )
		{
		//	Client :: isActive = true;
		//	Keys :: isActive = true;
			for ( r_si32 i = 0; i < ServerInfo_DeviceControllNum; ++i ) {
				deviceControll[i].beginInput();
			}
			deviceKeys.beginInput();
		}
		//! キー入力終了、入力状況を基に簡単に取り出し可能なキー情報を作成
		/*!
		*/
		void ServerWin32 :: endInput ( void )
		{
			for ( r_si32 i = 0; i < ServerInfo_DeviceControllNum; ++i ) {
				deviceControll[i].endInput();
			}
			deviceKeys.endInput();
		}
	}
}

#endif // R_TARGET_COMMONIS(R_TARGET_COMMON_WIN32) || R_TARGET_COMMONIS(R_TARGET_COMMON_WIN64)
